package org.gpp.proj1.communication.protocol;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.gpp.proj1.logic.core.board.RobotPosition;
import org.gpp.proj1.logic.metadata.RobotEntry;
import org.gpp.proj1.logic.metadata.RobotPartCategory;

/**
 * Class that build protocol messages for the request handlers
 *  
 * @author Paolo Victor, paolovictor@gmail.com
 */
public class ProtocolMessageFactory {

	public static Message buildChatMessage( String clientAlias, String message ) {

		String[] parameters = new String[2];
		parameters[ ProtocolParameters.CHAT_MESSAGE_ALIAS ] = clientAlias;
		parameters[ ProtocolParameters.CHAT_MESSAGE_TEXT ] = message;
		
		return new Message( ProtocolIdentifiers.CHAT, new String[]{ clientAlias, message } );
	}

	public static Message buildClientOfflineMessage(String offlineClient) {
		
		String[] parameters = new String[1];
		parameters[ ProtocolParameters.CLIENTOFFLINE_MESSAGE_ID ] = offlineClient;

		return new Message( ProtocolIdentifiers.CLIENTOFFLINE, new String[]{ offlineClient } );
	}

	public static Message buildHelloMessage( String alias ) {
		
		String[] parameters = new String[1];
		parameters[ ProtocolParameters.HELLO_MESSAGE_ALIAS ] = alias;
		
		return new Message( ProtocolIdentifiers.HELLO, parameters );
	}

	public static Message buildWhosHereMessage(Map<String, String> aliasMap, Set<String> readyClients) {

		int numClients = aliasMap.size();
		int numReadyClients = readyClients.size();

		// 1 for number of clients 
		// numClients * 2 for each client id -> alias mapping
		// 1 for number of ready clients
		// numReadyClients for each ready client id
		String[] parameters = new String[ 1 + numClients * 2  + 1 + numReadyClients ];
		
		parameters[ ProtocolParameters.WHOSHERE_MESSAGE_NUMCLIENTS ] = String.valueOf( numClients );
		
		int i = 1;
		for( String clientId : aliasMap.keySet() ) {
			parameters[ i ] = clientId;
			parameters[ i + 1 ] = aliasMap.get( clientId );
			i += 2;
		}
		
		i = 1 + numClients * 2;
		parameters[i] = String.valueOf( numReadyClients );
		
		i = 1 + numClients * 2 + 1;
		for( String clientId : readyClients ) {
			parameters[ i ] = clientId;
			i++;
		}
		
		return new Message( ProtocolIdentifiers.WHOSHERE, parameters );
	}
	
	public static Message buildChangeMapMessage( String mapName ) {
		
		String[] parameters = new String[1];
		parameters[ ProtocolParameters.CHANGEMAP_MESSAGE_MAP_NAME ] = mapName;
		
		return new Message( ProtocolIdentifiers.CHANGEMAP, parameters );
	}
	
	public static Message buildServerNameMessage( String serverName ) {
		
		String[] parameters = new String[1];
		parameters[ ProtocolParameters.SERVERNAME_MESSAGE_SERVER_NAME ] = serverName;
		
		return new Message( ProtocolIdentifiers.SERVERNAME, parameters );
	}

	public static Message buildToggleReadinessMessage() {

		return new Message( ProtocolIdentifiers.TOGGLEREADINESS, new String[]{} );
	}

	public static Message buildStartInitPhase() {
		
		return new Message( ProtocolIdentifiers.INITPHASE, new String[]{} );
	}

	public static Message buildMyRobotListMessage(String alias, List<RobotEntry> playerRobots) {

		// Format:
		// <alias> <numberofrobots> <robotname> <head> <torso> <armleft> <armright> <legs>
		String[] parameters = new String[ 2 + playerRobots.size() * 6 ];
		
		parameters[ ProtocolParameters.MYROBOTLIST_PLAYER_ALIAS ] = alias;
		parameters[ ProtocolParameters.MYROBOTLIST_NUMBER_OF_ROBOTS ] = String.valueOf( playerRobots.size() );
		
		int k = 0;
		for( RobotEntry robot : playerRobots ){
			parameters[ k * 6 + 2 ] = robot.getRobotName();
			parameters[ k * 6 + 3 ] = robot.getPart( RobotPartCategory.HEAD ).getName();
			parameters[ k * 6 + 4 ] = robot.getPart( RobotPartCategory.TORSO ).getName();
			parameters[ k * 6 + 5 ] = robot.getPart( RobotPartCategory.ARM_LEFT ).getName();
			parameters[ k * 6 + 6 ] = robot.getPart( RobotPartCategory.ARM_RIGHT ).getName();
			parameters[ k * 6 + 7 ] = robot.getPart( RobotPartCategory.LEGS ).getName();
			
			k++;
		}
		
		return new Message( ProtocolIdentifiers.MYROBOTDATA, parameters );
	}

	public static Message buildMapDataMessage(String gameMapString) {

		String[] parameters = new String[1];
		parameters[ ProtocolParameters.MAPDATA_DATA ] = gameMapString;
		
		return new Message( ProtocolIdentifiers.MAPDATA, parameters );
	}

	public static Message buildPlayerRobotDataMessage( String clientID, String[] data ) {
		String[] parameters = new String[ 1 + data.length ];
		
		parameters[ ProtocolParameters.PLAYERROBOTDATA_ID ] = clientID;
		parameters[ ProtocolParameters.PLAYERROBOTDATA_NUMROBOTS ] = data[0];
		
		for( int k = 1; k < data.length; k++ ) {
			parameters[k + 1] = data[k];
		}
		
		return new Message( ProtocolIdentifiers.PLAYEROBOTDATA, parameters );
	}

	public static Message buildGameBoardMessage(Map<String, Map<String, RobotPosition>> boardPositions) {

		/*
		 * - 1 is the number of clients
		 * - for each client, client + number of robots + number of robots * ( name, facing, x, y )   
		 */
		
		int elements = 1;
		for( String clientId : boardPositions.keySet() ) {			
			elements += 2 + boardPositions.get( clientId ).size() * 4;
		}
		
		String[] parameters = new String[ elements ];
		parameters[0] = String.valueOf( boardPositions.keySet().size() );
		
		int i = 1;
		for( String clientId : boardPositions.keySet() ) {
			Map<String, RobotPosition> robots = boardPositions.get( clientId );
			int numRobots = robots.size();

			parameters[i] = clientId;
			parameters[i + 1] = String.valueOf( numRobots );
			
			int robotOffset = 0;
			for( String robotName : robots.keySet() ) {
				RobotPosition robotPosition = robots.get( robotName );
				
				parameters[i + 2 + robotOffset] = robotName;
				parameters[i + 3 + robotOffset] = String.valueOf( robotPosition.getFacing().ordinal() );
				parameters[i + 4 + robotOffset] = String.valueOf( robotPosition.getX() );
				parameters[i + 5 + robotOffset] = String.valueOf( robotPosition.getY() );
				
				robotOffset += 4;
			}
			
			i += 2 + numRobots * 4;
		}
		
		return new Message( ProtocolIdentifiers.GAMEBOARDDATA, parameters );
	}

	public static Message buildStartInGamePhase() {
		
		return new Message( ProtocolIdentifiers.INGAMEPHASE, new String[]{} );
	}

	public static Message buildWhoseTurnIsIt() {
		
		return new Message( ProtocolIdentifiers.WHOSETURNISIT, new String[]{} );
	}

	public static Message buildCurrentTurnMessage(String clientId) {
		
		String[] parameters = new String[1];
		parameters[ ProtocolParameters.CURRENTTURN_PLAYER_ID ] = clientId;
		
		return new Message( ProtocolIdentifiers.CURRENTTURN, parameters );
	}

	public static Message buildYourTurnMessage() {
		
		return new Message( ProtocolIdentifiers.YOURTURN, new String[]{} );
	}

	public static Message buildCurrentTurnRobotMessage(String currentTurnRobot) {
		
		String[] parameters = new String[1];
		parameters[ ProtocolParameters.CURRENTTURNROBOT_ROBOT_NAME ] = currentTurnRobot;
		
		return new Message( ProtocolIdentifiers.CURRENTTURNROBOT, parameters );
	}

	public static Message buildEndTurn() {
		
		String[] parameters = new String[0];
		
		return new Message( ProtocolIdentifiers.ENDTURN, parameters );
	}

	public static Message buildMovedRobotMessage(String robot, int newX, int newY) {
		
		String[] parameters = new String[3];
		parameters[0] = robot;
		parameters[1] = String.valueOf( newX );
		parameters[2] = String.valueOf( newY );

		return new Message( ProtocolIdentifiers.MOVEROBOT, parameters );
	}

	public static Message buildPlayerMovedRobot(String client, String robot, int x, int y) {
		
		String[] parameters = new String[4];
		parameters[0] = client;
		parameters[1] = robot;
		parameters[2] = String.valueOf( x );
		parameters[3] = String.valueOf( y );

		return new Message( ProtocolIdentifiers.ROBOTMOVED, parameters );
	}

	public static Message buildRobotAttackedMessage(String robot, int selectedX, int selectedY, String selectedPart, String selectedAttack) {

		String[] parameters = new String[5];
		parameters[0] = robot;
		parameters[1] = String.valueOf( selectedX );
		parameters[2] = String.valueOf( selectedY );
		parameters[3] = selectedPart;
		parameters[4] = selectedAttack;

		return new Message( ProtocolIdentifiers.ATTACK, parameters );
	}

	public static Message buildPlayerAttacked(String client, String robot, int x, int y, String part, String attack) {
		
		String[] parameters = new String[6];
		parameters[0] = client;
		parameters[1] = robot;
		parameters[2] = String.valueOf( x );
		parameters[3] = String.valueOf( y );
		parameters[4] = part;
		parameters[5] = attack;

		return new Message( ProtocolIdentifiers.PLAYERATTACKED, parameters );
	}
}
